#include <string>
#include <cstdio>

#define LOG_INFO(fmt, ...)          printf("[I] %s:%d [%s] " fmt "\n", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)
#define LOG_ERROR(errnum, fmt, ...) printf("[E] %s:%d [%s] errnum=%d " fmt "\n", __FILE__, __LINE__, __FUNCTION__, errnum, ##__VA_ARGS__)

/**
 * @brief      中国大陆身份证号合法性验证
 * @param[in]  num : h身份证号
 * @retval     true : 合法
 * @retval     false : 不合法
 */
bool IDCardVerify(const std::string & num)
{
    int len = num.length();
    /*
     * 判断长度是否合法
     */
    if(18 != len)
    {        
        LOG_ERROR(-1, "Illegal length of ID number:%s", num.c_str());
        return false;
    }

    /*
     * 判断字符是否合法
     */
    bool ret = true;
    int S = 0; /* 17位数字各位数字与对应的加权因子的乘积:S */
    const char weightBuf[17] = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};

    for(int i = 0; ret && (i < (len - 1)); i++)
    {
        ret = ret && std::isdigit(num[i]);
        S += (num[i] - '0') * weightBuf[i]; 
    }
    ret = ret && ( std::isdigit(num[len - 1]) || ('X' == num[len - 1]) );
    if(!ret)
    {
        LOG_ERROR(-1, "Illegal ID number:%s", num.c_str());
        return false;
    }

    /*
     * 校验最后一位
     */

    /* 计算S除以11的余数T */
    char T = S % 11;

    /* 计算 (12 - T)/11的余数 R, 如果 R==10，校验码为字母“X”；如果R!=10，校验码为数字“R” */
    char R = (12 - T) % 11;
    char checkCode = (R == 10) ? 'X' : R + '0';
    ret = ret && (checkCode == num[len - 1]);
    if(!ret)
    {
        LOG_ERROR(-1, "The check code should be %c, but actually it is %c", checkCode, num[len - 1]);
        return false;
    }
    
    return ret;
}

/**
 * @brief      中国大陆身份证号合法性验证，校验码使用查表发
 * @param[in]  num : h身份证号
 * @retval     true : 合法
 * @retval     false : 不合法
 */
bool IDCardVerify2(const std::string & num)
{
    int len = num.length();
    /*
     * 判断长度是否合法
     */
    if(18 != len)
    {        
        LOG_ERROR(-1, "Illegal length of ID number:%s", num.c_str());
        return false;
    }

    /*
     * 判断字符是否合法
     */
    bool ret = true;
    int S = 0; /* 17位数字各位数字与对应的加权因子的乘积:S */
    const char weightBuf[17] = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};

    for(int i = 0; ret && (i < (len - 1)); i++)
    {
        ret = ret && std::isdigit(num[i]);
        S += (num[i] - '0') * weightBuf[i]; 
    }
    ret = ret && ( std::isdigit(num[len - 1]) || ('X' == num[len - 1]) );
    if(!ret)
    {
        LOG_ERROR(-1, "Illegal ID number:%s", num.c_str());
        return false;
    }

    /*
     * 校验最后一位
     */

    /* 计算S除以11的余数T */
    char T = S % 11;
    const char checkTable[11] = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};
    ret = ret && (checkTable[T] == num[len - 1]);
    if(!ret)
    {
        LOG_ERROR(-1, "The check code should be %c, but actually it is %c", checkTable[T], num[len - 1]);
        return false;
    }
    
    return ret;
}

int main(int argc, const char *argv[])
{
    if(2 != argc)
    {
        return -1;
    }

    if(IDCardVerify2(argv[1]))
    {
        LOG_INFO("Verification passed");
    }
    
    return 0;
}
